from __future__ import unicode_literals

import uuid
from collections import Counter

from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.utils.encoding import python_2_unicode_compatible
from django.conf import settings
from django.db import models
from markdownx.models import MarkdownxField

from markdownx.utils import markdownify
from slugify import slugify
from taggit.managers import TaggableManager


@python_2_unicode_compatible
class Vote(models.Model):
    """使用Django中的CententType,同时关联对问题和回答的投票"""
    uuid_id = models.UUIDField(primary_key=True,default=uuid.uuid4,editable=False)
    user = models.ForeignKey(settings.AUTH_USER_MODEL,related_name='qa_vote',
                             on_delete=models.CASCADE,verbose_name='用户')
    value = models.BooleanField(default=True,verbose_name="赞同或反对")
    # GenericForeignKey设置
    content_type = models.ForeignKey(ContentType,related_name="votes_on",
                                     on_delete=models.CASCADE)
    object_id = models.CharField(max_length=255)  # 其他模型的主键id
    vote = GenericForeignKey('content_type','object_id')

    created_at=models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at=models.DateTimeField(auto_now=True, verbose_name="更新时间")

    class Meta:
        verbose_name = "投票"
        verbose_name_plural = verbose_name
        # 联合唯一约束,一个用户只能给一个模型的一个记录投票
        unique_together = ['user','content_type','object_id']
        # SQL优化,联合唯一索引
        index_together = ['content_type','object_id']



@python_2_unicode_compatible
class QuestionQuerySet(models.query.QuerySet):
    """ 自定义QuerySet,提高模型类的可用性"""
    def get_answered(self):
        """获取已有答案的问题"""
        return self.filter(has_answer=True).select_related('user')

    def get_unanswered(self):
        """未被回答的问题"""
        return self.filter(has_answer=False).select_related('user')

    def get_counted_tags(self):
        """统计所有问题中,每一个标签的数量(大于0)"""
        tag_dict = {}
        for obj in self.all().annotate(tagged=models.Count('tags')).filter(tags__gt=0):
            for tag in obj.tags.names():
                if tag not in tag_dict:
                    tag_dict[tag] = 1
                else:
                    tag_dict[tag] += 1
        return tag_dict.items()


@python_2_unicode_compatible
class Question(models.Model):
    STATUS = (("O","Open"),("C","Close"),("D","Draft"))

    user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,
                           related_name='q_author', verbose_name='提问者')
    title = models.CharField(max_length=255,unique=True,verbose_name='标题')
    slug = models.SlugField(max_length=255, null=True,blank=True,verbose_name='URL别名')
    status = models.CharField(max_length=1, choices=STATUS, default="O",
                              verbose_name="问题状态")
    content = MarkdownxField(verbose_name="内容")
    tags = TaggableManager(help_text='多个标签使用,(英文)隔开', verbose_name="标签")
    has_answer = models.BooleanField(default=False,verbose_name="接受回答")  # 是否接受回答
    created_at = models.DateTimeField(db_index=True,auto_now_add=True,verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

    votes = GenericRelation(Vote,verbose_name="投票情况") # 用于反向查询,不生成字段

    objects = QuestionQuerySet.as_manager()

    class Meta:
        verbose_name ="问题"
        verbose_name_plural = verbose_name
        ordering = ["-created_at"]

    def __str__(self):
        return self.title

    def save(self,*args,**kwargs):
        if not self.slug:
            self.slug = slugify(self.title)
        return super(Question,self).save(*args,**kwargs)

    def get_markdown(self):
        return markdownify(self.content)

    def total_votes(self):
        """得票数"""
        # Counter赞同票多少，反对票多少
        dic = Counter(self.votes.values_list('value',flat=True))
        return dic[True] - dic[False]

    def get_answers(self):
        """获取所有问题的回答"""
        return Answer.objects.filter(question=self).select_related('user','question')

    def count_answers(self):
        """获取所有问题的回答数量"""
        return self.get_answers().count()

    def get_upvoters(self):
        """赞同的用户"""
        return [vote.user for vote in self.votes.filter(value=True).select_related('user').prefetch_related('votes')]

    def get_downvoters(self):
        """反对的用户"""
        return [vote.user for vote in self.votes.filter(value=False).select_related('user').prefetch_related('votes')]

    # def get_accepted_answer(self):
    #     """被接受的回答"""
    #     return Answer.objects.get(question=self,is_answer=True)

@python_2_unicode_compatible
class Answer(models.Model):
    uuid_id = models.UUIDField(primary_key=True,default=uuid.uuid4,editable=False)
    user = models.ForeignKey(settings.AUTH_USER_MODEL,related_name='a_author',
                             on_delete=models.CASCADE,verbose_name="回答者")
    question = models.ForeignKey(Question,on_delete=models.CASCADE,verbose_name="问题")
    content = MarkdownxField(verbose_name="回答内容")
    is_answer = models.BooleanField(default=False,verbose_name="回答是被接受")
    created_at=models.DateTimeField(db_index=True,auto_now_add=True, verbose_name="创建时间")
    updated_at=models.DateTimeField(auto_now=True, verbose_name="更新时间")

    votes=GenericRelation(Vote, verbose_name="投票情况")  # 用于反向查询,不生成字段

    class Meta:
        verbose_name = "回答"
        verbose_name_plural = verbose_name
        ordering = ['-is_answer','-created_at']

    def __str__(self):
        return self.content

    def get_markdown(self):
        return markdownify(self.content)

    def total_votes(self):
        """得票数"""
        # Counter赞同票多少，反对票少数
        dic = Counter(self.votes.values_list('value',flat=True))
        return dic[True] - dic[False]

    def get_upvoters(self):
        """赞同的用户"""
        return [vote.user for vote in self.votes.filter(value=True)]

    def get_downvoters(self):
        """反对的用户"""
        return [vote.user for vote in self.votes.filter(value=False)]

    # def get_accepted_answer(self):
    #     """被接受的回答"""
    #     return Answer.objects.get(question=self,is_answer=True)

    def accept_answer(self):
        """接受回答---一个问题只能采取一个回答为正确答案"""
        """接受回答时需要把Question模型类的has_answer,Answer模型类的is_answer设置为True"""
        # 查看当前问题的所有回答
        answer_set = Answer.objects.filter(question=self.question)
        answer_set.update(is_answer=False)
        # 接受当前回答并保存
        self.is_answer = True
        self.save()
        # 该问题已有被接受的回答
        self.question.has_answer = True
        self.question.save()


# 1. 需要返回查询集的逻辑写在QuerySetModel
# 2. 模型类中数据库处理的逻辑写在Models
# 3. 业务相关逻辑的处理写在Views



